<?php

class MY_Model extends Model {

	var $nombreTabla;
	var $idT1;
	var $nombreCampo='nombre';

	var $tituloListado = "Listado";
	var $tituloCrear = "Crear";
	var $tituloModificar = "Modificar";
	
	var $tipoListado=0;// $sinabuelo 0-> con abuelo

	var $opcionListar = true;
	var $opcionCrear = true;
	var $opcionBuscar = true;

	var $listadoTabla = NULL;
	var $filtro = NULL;
	
	// Metadatos

	var $camposBusqueda=array();  //campo=>label

	// Caracteristicas de los campos
	var $campos=array();
	// Hijos que posee la tabla. Contiene informacion
	// particular sobre el modelo actual
	var $hijos = array();
	var $importar = array();
	//Opciones especificas de cada modelo (que no estan con el conquer)
	var $extras = array();

	var $condicion = array();
	var $orderby = '';
	var $groupby = '';

	// Indica si en el array de retorno se devuelve con el nombre del campo o autonumeracion
	var $keyField = false;

	function MY_Model()
	{
		// Call the Model constructor
		parent::Model();
	}

	/**
	 * Proxy de Seguridad
	 * @param $funcion
	 * @param $param1
	 * @param $param2
	 * @param $param3
	 * @param $param4
	 * @return unknown_type
	 */
	function secProxy($funcion,$param1=null,$param2=null,$param3=null,$param4=null)
	{
		$modelo=strtolower(get_class($this));
		if (strpos($modelo,'view')===0) $modelo=substr($modelo,4); //en el caso de vista tiene los mismos permisos que para el modelo 
		$retorno=array();
		$aux=true;
		switch($funcion){
			case 'getIdNombre': $retorno=$this->getIdNombre();
			break; 
			case 'getciudadData':if ($modelo=='ciudad') $retorno=$this->getData();
			break;
			case 'getTipoDeUsuarioData':if ($modelo=='tipodeusuario') $retorno=$this->getData();
			break;
			case 'getespecialidadData':if ($modelo=='especialidad') $retorno=$this->getData();
			break;
			case 'congresogetData':if ($modelo=='congreso') $retorno=$this->getData();
			break;
			case 'logingetData': if ($modelo=='usuario') $retorno=$this->getData();
			break;
			case 'cursogetData': if ($modelo=='curso') $retorno=$this->getData($param1, $param2);
			break;
			case 'modificarSinPostDS': if ($modelo=='datosesion') $retorno=$this->modificarSinPost($param1,$param2);
			break;
			case 'insertarSinPostDS': if ($modelo=='datosesion') $retorno=$this->insertarSinPost($param1,$param2);
			break;
			case 'getData':	if ($this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->getData($param1,$param2);
			}
			break;
			case 'getPosicion':if ($this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->getPosicion($param1);
			}
			break;
			case 'getRowData':if ($this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->getRowData($param1);
			}
			break;
			case 'getRow':	if ($aux = $this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->getRow($param1);
			}
			break;
			case 'insertar': if (($aux = $this->sesion->existe(array('privilegios',$modelo,'agregar'))) > 0 ){;
			//$aux=true;
			if ($aux==2){
				$aux=$this->acotarScope('i');
			}
			if ($aux) $retorno=$this->insertar($param1,$param2,$param3);
			}
			break;
			case 'insertarSinPost': if (($aux = $this->sesion->existe(array('privilegios',$modelo,'agregar'))) > 0 ){
				//$aux=true;
				if ($aux==2){
					$aux=$this->acotarScope('isp',$param1);
				}
				if ($aux) $retorno=$this->insertarSinPost($param1,$param2);
			}
			break;
			case 'modificar': if (($aux = $this->sesion->existe(array('privilegios',$modelo,'modificar'))) > 0 ){
				//$aux=true;
				$tipoPermiso = $aux; 
				if ($aux==2){
					$aux=$this->acotarScope('m');
				}
				if ($aux) $retorno=$this->modificar($param1,$tipoPermiso,$param2);
			}
			break;
			case 'modificarSinPost': if (($aux = $this->sesion->existe(array('privilegios',$modelo,'modificar'))) > 0 ){
				//$aux=true;
				if ($aux==2){
					$aux=$this->acotarScope('msp',$param1);
				}
				if ($aux) $retorno=$this->modificarSinPost($param1,$param2);
			}
			break;
			case 'eliminar': if ($this->sesion->existe(array('privilegios',$modelo,'eliminar'))){
				//$aux=true;
				if ($this->sesion->existe(array('privilegios',$modelo,'eliminar'))==2){
					$aux=$this->acotarScope('m',$param1);
				}
				if ($aux) $retorno=$this->eliminar($param1);
			}
			break;
			case 'getIdNombre': if ($this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->getIdNombre();
			}
			break;
			case 'busqueda_gen': if ($this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->busqueda_gen($param1,$param2,$param3);
			}
			break;
			case 'paginacion':if ($this->sesion->existe(array('privilegios',$modelo,'ver'))){
				if ($this->sesion->existe(array('privilegios',$modelo,'ver'))==2){
					$this->acotarScope('v');
				}
				$retorno=$this->paginacion($param1, $param2);
			}
			break;
		}

		if(!$aux) {
			$this->sesion->set_userdata('error',"<p>No posee permisos para la accion solicitada!</p>");
		}

		return $retorno;
	}
	 

	/**
	 * Trae los metadatos de las relaciones "Parte de" del array de entrada
	 * @param $datos
	 * @return unknown_type
	 */
	function getPartof($datos = ''){
		// TODO $this getCampos() (== getRowMetaData()) y $this getCamposKey() (== fields()) o algo asi
		if ($datos=='')$datos=$this->campos;
		$campos = array();
		foreach ($datos as $campo){
			if ($campo['clase']=='partof'){
				$campos = $campo;
				break;
			}
		}
		return $campos;

	}


	/**
	 * Trae los metadatos de los campos foraneos del array de entrada
	 * @param $datos
	 * @return unknown_type
	 */
	function getForaneas($datos = ''){
		if ($datos=='')$datos=$this->campos; // TODO $this getCampos() == getRowMetaData()
		$campos = array();
		foreach ($datos as $campo){
			if (isset($campo['modelo']) && $campo['clase']!='partof'){
				$campos[] = $campo;
			}
		}
		return $campos;

	}

	/**
	 * Elimina los metadatos de los campos foraneos del array de entrada
	 * @param $datos
	 * @return unknown_type
	 */
	function limpiarForaneas($datos){
		$campos = $datos;
		$i=0;
		foreach ($datos as $campo){
			if (isset($campo['modelo'])){
				unset($campos[$i]);
			}
			$i++;
		}
		return $campos;

	}

	/**
	 * Trae los valores de los campos foraneos del array de entrada
	 * @param $datos
	 * @param $valores
	 * @return unknown_type
	 */
	function getForaneasData($datos,$valores){
		$campos = array();
		$icolumna = 0;
		foreach ($datos as $campo){
			if (isset($campo['modelo']) && $campo['clase']!='partof'){
				$campos[]=$valores[$icolumna];
			}
			$icolumna++;
		}
		return $campos;

	}

	/**
	 * Elimina los valores de los campos foraneos del array de entrada
	 * @param $datos
	 * @param $valores
	 * @return unknown_type
	 */
	function limpiarForaneasData($datos,$valores){
		$campos = $valores;
		$i = 0;
		foreach ($datos as $campo){
			if (isset($campo['modelo'])){
				unset($campos[$i]);
			}
			$i++;
		}
		return $campos;

	}

	/**
	 * 
	 * @param $campo
	 * @param $val
	 * @return unknown_type
	 */
	function setCondicion($campo,$val = NULL){
	
		if (is_array($campo)) {
			$this->condicion = array_merge($this->condicion,$campo);
		} else {	
			$this->condicion[$this->nombreTabla.'.'.$campo] = $val;
		}
	}

	function removeCondicion(){
		$this->condicion = array();
	}

	function setOrderBy($val){
		$this->orderby = $val;
	}

	function setGroupBy($val){
		$this->groupby = $val;
	}

	// TODO Agregar array_values($auxMetadata), y $this->campos; agregarle el como key realname!!
	// O $this->getCampos() == getRowMetaData()
	function getMetaData()
	{
		$auxMetadata=$this->campos;
		$auxMetadata[]= array("realname" =>$this->idT1,
					"clase" => "id",
					"label" => "",
					"rules" => "integer");
		
		return $auxMetadata;
	}

	function setKeyField($valor){
		$this->keyField = $valor;
	}

	/**
	 * Hook
	 */
	protected function accinesAntesDeGetData(){}
	/**
	 * 
	 * @return unknown_type
	 */
	protected function accinesDepuesDeGetData($resultado){
		return $resultado;
	}
	
	/**
	 * 
	 * @param $limit
	 * @param $offset
	 * @return unknown_type
	 */
	private function getData($limit = NULL, $offset = NULL)
	{
		// Hook antes de consultar la base de datos
		$this->accinesAntesDeGetData();
	
		if (count($this->condicion)) { $this->db->where($this->condicion); }
		if ($this->orderby != '') { $this->db->order_by($this->orderby); } else {$this->db->order_by($this->nombreTabla.'.'.$this->idT1);}
		//Query the data table for every record and row
		$this->db->limit($limit, $offset);

		$this->db->from($this->nombreTabla);

		$query = $this->db->get();
//echo '<pre>'; print_r($this->db->last_query()); echo '</pre>'; 
		if ($query->num_rows() > 0)
		{
			$auxValores=array();

			$resultados=$query->result_array();
			if ($this->keyField === true) { // Devolver como viene, con nombre de las columnas
					
				$laKey = $this->getIdKey();
				$tmpResultado = array();
				foreach ($resultados as $resultado) {
					$tmpResultado[$resultado[$laKey]] = $resultado;
				}
				$elResultado = $tmpResultado;

			} else { // if ($this->keyField === false) { // Devolver con autonumeracion
					
				foreach ($resultados as $resultado){
					$auxCampos=array();
					// TODO $this getCamposKey() (== fields() ) as $key => $campo
					foreach ($this->campos as $campo){
						$auxCampos[]=$resultado[$campo['realname']];
					}
					$auxCampos[]= $resultado[$this->idT1];
					$auxValores[$resultado[$this->idT1]]=$auxCampos;
				}
				$elResultado = $auxValores;

			} /*else {
			// Se entiende que se pasa el nombre del campo que quiere poner como key
			$auxValores = array();
			foreach ($resultados as $resultado){
			$auxValores[$this->keyField]=$resultado;
			}
			return $auxValores;
				
			}*/
		}else{
			$elResultado = array();
		}
		
		
		// Hook despues de buscar los datos
		return $this->accinesDepuesDeGetData($elResultado);
		
		
	}

	function getRowMetaData()
	{
		// TODO Agregar array_values($auxMetadata)
		// a que se refuere el Row?
		return $this->campos;
	}

	private function getRowData($id) // ??
	{
		$this->db->where($this->nombreTabla.'.'.$this->idT1, $id);
		$this->db->from($this->nombreTabla);
		$query = $this->db->get();

		if ($query->num_rows() > 0)
		{
			$aux=array();
			$resultado=$query->result_array();
			$resultado=$resultado[0];
			$auxValores=array();
			//$auxCampos[]= $resultado[$this->idT1];
			foreach ($this->campos as $campo){
				$auxValores[]=$resultado[$campo['realname']];
			}

			return $auxValores;
		}else{
			return array();
		}
	}


	private function getRow($id)
	{
		$this->db->where($this->nombreTabla.'.'.$this->idT1, $id);
		$this->db->from($this->nombreTabla);
		$query = $this->db->get();
		$rs = array();
		if ($query->num_rows() > 0)
		{
			$rs = $query->result_array();
				
		}else{
			//show_error('Database is empty!');
		}
		if ($query->num_rows() > 0)
		return $rs[0];
		return $rs;
	}

	function validacion()
	{
		$rules=array();
		foreach ($this->campos as $campo){
			$rules[$campo['realname']]	= $campo['rules'];
		}
		return $rules;
	}

	/**
	 * Utilizada en las reglas de validacion
	 * @return unknown_type
	 */
	function fields()
	{
		$fields=array();
		foreach ($this->campos as $campo){
			$fields[$campo['realname']]	= $campo['realname'];
		}
		return $fields;
	}

	/**
	 * Devuelve los metadatos con keyfield igual al nombre real del campo
	 * @return unknown_type
	 */
	function getCamposKey()
	{
		$fields=array();
		$fields[$this->idT1]= array("realname" =>$this->idT1,
					"clase" => "id",
					"label" => "",
					"rules" => "integer");
		
		foreach ($this->campos as $campo){
			$fields[$campo['realname']]	= $campo;
		}
		return $fields;
	}

	function preparaInsertar()
	{
		$aux=array();
		foreach($this->campos as $campo){
			if ($campo['clase']=="foranea")
			$aux[]=$campo['modelo'];
		}
		return $aux;

	}

	/**
	 * 
	 * @param $foreign
	 * @param $file
	 * @param $parent
	 * @return unknown_type
	 */
	private function insertar($foreign,$file='',$parent)
	{

		$data=array();
		
		foreach($this->campos as $campo){

			switch ($campo['clase']){
				case "foranea":
					$data[$campo['realname']] = $foreign[$campo['modelo']];
					break;
				case "file":
					if (isset($file[$campo['realname']])) {
						$data[$campo['realname']] = $file[$campo['realname']];
					} else {
						$data[$campo['realname']] = '';
					}
					break;
				case "boolean":
					if ($this->input->post($campo['realname'])=='true')
					$data[$campo['realname']] = '1';
					else
					$data[$campo['realname']] = '0';
					break;
				case "datetime":
					break;
				case "password":
					$data[$campo['realname']] = md5($this->input->post($campo['realname']));
					break;
				default:
					$data[$campo['realname']] = $this->input->post($campo['realname']);
			}
		}


		return $this->insertarSinPost($data, $parent);
	}

	/**
	 * 
	 * @param $data
	 * @param $parent
	 * @return unknown_type
	 */
	protected function insertarSinPost($data,$parent=null)
	{
		$data = $this->accionesAntesDeInsertar($data, $parent);
		/*
		echo '<PRE>';
		print_r($data);
		echo '<PRE>';
		exit();
		*/
		$exito=$this->db->insert($this->nombreTabla, $data);
		if (!$exito) echo $this->sesion->set_userdata('error',"<p>No se han insertado los datos, verifique que sean correctos</p>");

		$elId = $this->db->insert_id();

		// verificar id.. si se identifica como de error.. puede ser?
		// no ejecutar el metodo.
		$this->accionesAlInsertar($elId, $parent);

		return $elId;
	}

	/**
	 * Hook
	 * @param $data
	 * @param $parent
	 * @return $data Posiblemente Modificado
	 */
	protected function accionesAntesDeInsertar($data, $parent) {
		return $data;
	}
	
	/**
	 * Hook
	 * @param $elId
	 * @param $parent
	 * @return unknown_type
	 */
	protected function accionesAlInsertar($elId, $parent) {	}


	/**
	 * 
	 * @param $file
	 * @return unknown_type
	 */
	private function modificar($file='',$tipoPermiso=1,$parent=null)
	{
		$aux=array();

		$data=array();
		foreach($this->campos as $campo){
			/*
			 * Cuando un campo tiene una key estatico definido con 
			 * 1 => entonces para cualquier tipo de usuario el dato es estatico 
			 * 2 => entonces solo para los tipo de usuarios que pueden editar solo sus propios datos
			 * (tipo 2) el dato es estatico
			 */ 
			if (isset($campo['estatico'])) {
				if ($campo['estatico'] == 1) {
					$campo['clase'] = 'estatico';
				} elseif ($campo['estatico'] == 2){
					if ($tipoPermiso != 1){
						$campo['clase'] = 'estatico';
					}
				}
			}
			switch ($campo['clase']){
				case "estatico":
					break;
				case "file":
					/*if (isset($file[$campo['realname']])){
						if ($file[$campo['realname']]!='')$data[$campo['realname']] = $file[$campo['realname']];
					}*/
					if (isset($file[$campo['realname']])) {
						$data[$campo['realname']] = $file[$campo['realname']];
					} else {
						//$data[$campo['realname']] = '';
					}
					break;
				case "foranea":
					$aux[]=$campo['modelo'];
					break;
				case "boolean":
					if ($this->input->post($campo['realname'])=='true')
					$data[$campo['realname']] = '1';
					else
					$data[$campo['realname']] = '0';
					break;
				case "password":
					if ($this->input->post($campo['realname']) != ''){
						$data[$campo['realname']] = md5($this->input->post($campo['realname']));
					}
					break;
				default:
					$data[$campo['realname']] = $this->input->post($campo['realname']);

			}
		}

		$this->modificarSinPost( $this->input->post($this->idT1) , $data, $parent);
		
		return $aux; // ?
	}

	/**
	 * 
	 * @param $id
	 * @param $data
	 * @return unknown_type
	 */
	protected function modificarSinPost($id, $data,$parent = null)
	{
		$data = $this->accionesAntesDeModificar($data, $parent);
		
		$this->db->where($this->idT1,  $id);
		$exito=$this->db->update($this->nombreTabla, $data);
		if (!$exito) echo $this->sesion->set_userdata('error',"<p>No se han modificado los datos, verifique que sean correctos</p>");
		
		$this->accionesAlModificar($id, $parent);
		
	}

	/**
	 * Hook
	 * @param $data
	 * @param $parent
	 * @return $data Posiblemente Modificado
	 */
	protected function accionesAntesDeModificar($data, $parent) {
		return $data;
	}
	
	/**
	 * Hook
	 * @param $data
	 * @param $parent
	 * @return unknown_type
	 */
	protected function accionesAlModificar($data, $parent) {}	
	
	protected function eliminar($id)
	{
		$nombrecampo = $this->idT1;
		$exito=$this->db->delete($this->nombreTabla, array($nombrecampo => $id));
		if (!$exito) echo $this->sesion->set_userdata('error',"<p>No se han eliminado los datos, verifique que no hayan otras entidades que dependan de la que quiere eliminar</p>");
	}

	function getIdKey()
	{
		return $this->idT1;
	}

	function getNombreCampo()
	{
		return $this->nombreCampo;
	}


	private function getIdNombre()
	{
		//Query the data table for every record and row
		//$this->db->select($this->idT1.', '.$this->nombreCampo);
		$query = $this->db->get($this->nombreTabla);

		if ($query->num_rows() > 0)
		{
			$result = array();
			foreach ($query->result_array() as $resultado){
				$result[$resultado[$this->idT1]] = $resultado[$this->nombreCampo];
			}
			//print_r($result);
			return $result;
		}else{
			//return array();
			return NULL;
			//show_error('Database is empty!');
		}
	}

	/**
	 * Trae la posicion de la columna en el array
	 * @param $array
	 * @param $columna
	 * @return unknown_type
	 */
	function getIndexCampo($array,$columna)
	{
		switch ($columna) {
			case 'id': $columna=$this->idT1; break;
			case 'nombre': $columna=$this->nombreCampo; break;
		}
		$i=0;
		foreach ($array as $campo){
			if($campo['realname']==$columna) {
				break;
			}
			$i++;
		}
		if (count($array)==$i) return '-1';
		return $i;
	}


	/**
	 * 
	 * @param $campos_req
	 * @param $campos_where
	 * @return unknown_type
	 */
	private function busqueda_gen($campos_req = NULL, $campos_where = NULL,$limit = NULL){



		//Se definen los campos que se van a traer de la base de datos. Si es NULL se traen todos.
		if ($campos_req)
		{
			$dato = "";
			foreach($campos_req as $req)
			{
				$dato = $dato.$req.',';
			}

			$this->db->select($dato);

		}
		//Se define la tabla de donde se traeran datos
		$this->db->from($this->nombreTabla);

		//Se configura la clausula where con los datos del arreglo. Si el arreglo es nulo no hay clausulas...
		if (!empty($campos_where))
		{
			$this->db->where($campos_where);
		}

		if (!empty($limit)){
			$this->db->limit($limit);
		}

		if ($this->groupby != '') { $this->db->group_by($this->groupby); } 

		if ($this->orderby != '') { $this->db->order_by($this->orderby); } 
		//Se configura en caso de que las clausulas sean con uniones en vez de uniones y
		//$this->db->or_where('id >', $id);

		//Finalmente se realiza la consulta.
		$consulta = $this->db->get();
//echo '<pre>'; print_r($this->db->last_query()); echo '</pre>';
		$resultado['consulta'] = $consulta->result_array();
		$resultado['cant_filas'] = $consulta->num_rows();
		return $resultado;
	}


	private function getPosicion($id) 
	{
		$query = $query=$this->db->query('SELECT count(*) as cantidad from '.$this->nombreTabla.' WHERE '.$this->idT1.'<'.$id);

		$resultado=$query->result_array();
		$resultado=$resultado[0]['cantidad'];
		return $resultado;

	}

	
	function getCantidadRegistros(){
	
		 return $this->db->count_all($this->nombreTabla);
	}

	function getHijos()
	{

		return $this->hijos;
	}

	function getExtras($param=null)
	{
		if (!isset($param)){
			return $this->extras;
		}else{
			$aux=array();
			foreach($this->extras as $extra){
				if($extra['clase']==$param)
					$aux[]=$extra;
			}
//echo '<pre>';print_r($aux);echo '</pre>';exit;
			return $aux;
		}
	
	}

	/**
	 * Es sobreescrita por los modelos que la necesitan 
	 * (los que se encadenan de alguna manera con usuario)
	 * @param $param
	 * @return unknown_type
	 */
	protected function acotarScope($param=false)
	{
		return true;
	}
	function getImportar()
	{
		return $this->importar;
	}


	function getTituloListado()
	{
		return $this->tituloListado;
	}

	function getTituloCrear()
	{
		return $this->tituloCrear;
	}

	function getTituloModificar()
	{
		return $this->tituloModificar;
	}

	function setTituloListado($s)
	{
		$this->tituloListado = $s;
	}

	function setTituloCrear($s)
	{
		$this->tituloCrear = $s;
	}

	function setTituloModificar($s)
	{
		$this->tituloModificar = $s;
	}

	function getTipoListado()
	{
		return $this->tipoListado;
	}

	function mostrarOpcionListar(){
		return $this->opcionListar;
	}
	
	function mostrarOpcionCrear(){
		return $this->opcionCrear;
	}
	
	function mostrarOpcionBuscar(){
		return $this->opcionBuscar;
	}

	function getListadoTabla(){
		return $this->listadoTabla;
	}

	function getFiltro(){
		return $this->filtro;
	}
	//Cuando no se busca por todos los campos
	function getCamposBusqueda(){
		if (empty($this->camposBusqueda))
			return array($this->nombreCampo => $this->nombreCampo);
		return $this->camposBusqueda;
	}
	
}


?>
